package spi;

import cn.hutool.core.io.resource.ResourceUtil;
import faultTolerant.*;
import loadBalancer.*;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import register.EtcdRegistry;
import register.Registry;
import register.RegistryCategory;
import retry.FixedTimeIntervalStrategy;
import retry.NoRetryStrategy;
import retry.RetryStrategy;
import retry.RetryStrategyCategoryKeys;
import serializer.*;

/**
 * SPI 加载器
 * 负责加载框架内置与用户自定义的可插拔实现（序列化、注册中心、负载均衡、重试、容错等）。
 * 加载规则：优先读取自定义目录，其次读取系统目录，支持按 key 选择具体实现并进行单例缓存。
 */
@Slf4j
public class SpiLoader {
    /**
     * 存储已加载的实现映射：接口全限定名 => (实现 key => 实现类)
     */
    private static Map<String, Map<String, Class<?>>> loaderMap = new ConcurrentHashMap<>();

    /**
     * 实例缓存：实现类全限定名 => 单例对象实例
     */
    private static Map<String, Object> instanceCache = new ConcurrentHashMap<>();
    static {
        // 框架内置：序列化器
        loaderMap.put(Serializer.class.getName(), new HashMap<>() {
            {
                put(SerializerCategory.JdkKey, JdkSerializer.class);
            }
        });
        loaderMap.get(Serializer.class.getName()).put(SerializerCategory.JsonKey, JsonSerializer.class);
        loaderMap.get(Serializer.class.getName()).put(SerializerCategory.HessianKey, HessianSerializer.class);
        loaderMap.get(Serializer.class.getName()).put(SerializerCategory.KryoKey, KryoSerializer.class);

        // 单例实例缓存：序列化器
        instanceCache.put(SerializerCategory.JdkKey, new JdkSerializer());
        instanceCache.put(SerializerCategory.JsonKey, new JsonSerializer());
        instanceCache.put(SerializerCategory.HessianKey, new HessianSerializer());
        instanceCache.put(SerializerCategory.KryoKey, new KryoSerializer());
        
        // 框架内置：注册中心（etcd）
        loaderMap.put(Registry.class.getName(), new HashMap<>() {
            {
                put(RegistryCategory.ETCD, EtcdRegistry.class);
            }
        });

        // 单例实例缓存：注册中心（etcd）
        instanceCache.put(RegistryCategory.ETCD, new EtcdRegistry());

        // 框架内置：负载均衡（轮询、随机、一致性哈希）
        loaderMap.put(LoadBalance.class.getName(), new HashMap<>() {
            {
                put(LoadBalancerCategoryKey.ROUND_BALANCER, RoundBalancer.class);
            }
        });
        loaderMap.get(LoadBalance.class.getName()).put(LoadBalancerCategoryKey.RANDOM_BALANCER, RandomBalancer.class);
        loaderMap.get(LoadBalance.class.getName()).put(LoadBalancerCategoryKey.CONSISTENT_HASH_BALANCER,
                ConsistentHashBalancer.class);

        // 单例实例缓存：负载均衡
        instanceCache.put(LoadBalancerCategoryKey.ROUND_BALANCER, new RoundBalancer());
        instanceCache.put(LoadBalancerCategoryKey.RANDOM_BALANCER, new RandomBalancer());
        instanceCache.put(LoadBalancerCategoryKey.CONSISTENT_HASH_BALANCER, new ConsistentHashBalancer());

        // 框架内置：重试策略（不重试、固定间隔）
        loaderMap.put(RetryStrategy.class.getName(), new HashMap<>() {
            {
                put(RetryStrategyCategoryKeys.NoRetry, NoRetryStrategy.class);
            }
        });
        loaderMap.get(RetryStrategy.class.getName()).put(RetryStrategyCategoryKeys.FixedTimeRetry,
                FixedTimeIntervalStrategy.class);

        // 单例实例缓存：重试策略
        instanceCache.put(RetryStrategyCategoryKeys.NoRetry, new NoRetryStrategy());
        instanceCache.put(RetryStrategyCategoryKeys.FixedTimeRetry, new FixedTimeIntervalStrategy());

        // 框架内置：容错策略（故障转移/回退/快速失败/静默处理）
        loaderMap.put(FaultTolerant.class.getName(), new HashMap<>() {
            {
                put(FaultTolerantCategoryKeys.FAIL_OVER, FaultOver.class);
            }
        });
        loaderMap.get(FaultTolerant.class.getName()).put(FaultTolerantCategoryKeys.FAIL_BACK, FaultBack.class);
        loaderMap.get(FaultTolerant.class.getName()).put(FaultTolerantCategoryKeys.FAIL_FAST, FaultFastFail.class);
        loaderMap.get(FaultTolerant.class.getName()).put(FaultTolerantCategoryKeys.FAIL_SAFE, FaultSafe.class);

        // 单例实例缓存：容错策略
        instanceCache.put(FaultTolerantCategoryKeys.FAIL_OVER, new FaultOver());
        instanceCache.put(FaultTolerantCategoryKeys.FAIL_BACK, new FaultBack());
        instanceCache.put(FaultTolerantCategoryKeys.FAIL_FAST, new FaultFastFail());
        instanceCache.put(FaultTolerantCategoryKeys.FAIL_SAFE, new FaultSafe());

        // 支持用户通过 SPI 进行自定义实现接入
    }

    /**
     * 系统 SPI 目录
     */
    private static final String RPC_SYSTEM_SPI_DIR = "META-INF/RPC/sys/";

    /**
     * 自定义 SPI 目录
     */
    private static final String RPC_CUSTOM_SPI_DIR = "META-INF/RPC/custom/";

    /**
     * SPI 扫描目录优先级（自定义优先于系统）
     */
    private static final String[] SCAN_DIRS = new String[] { RPC_SYSTEM_SPI_DIR, RPC_CUSTOM_SPI_DIR };

    /**
     * 需要动态加载的接口列表
     */
    private static final List<Class<?>> LOAD_CLASS_LIST = Arrays.asList(Serializer.class);

    /**
     * 加载所有受支持的 SPI 接口的实现
     */
    public static void loadAll() {
        log.info("加载所有 SPI");
        for (Class<?> aClass : LOAD_CLASS_LIST) {
            load(aClass);
        }
    }

    /**
     * 获取某个 SPI 接口指定 key 的单例实现实例
     *
     * @param tClass SPI 接口类型
     * @param key    实现 key（在 SPI 文件或内置映射中声明）
     * @param <T>    实例泛型
     * @return       对应实现的单例实例
     */
    public static <T> T getInstance(Class<?> tClass, String key) {
        String tClassName = tClass.getName();
        Map<String, Class<?>> keyClassMap = loaderMap.get(tClassName);
        if (keyClassMap == null) {
            throw new RuntimeException(String.format("SpiLoader 未加载 %s 类型", tClassName));
        }
        if (!keyClassMap.containsKey(key)) {
            throw new RuntimeException(String.format("SpiLoader 的 %s 不存在 key=%s 的类型", tClassName, key));
        }
        // 目标实现类型
        Class<?> implClass = keyClassMap.get(key);
        // 从实例缓存中加载或创建单例
        String implClassName = implClass.getName();
        if (!instanceCache.containsKey(implClassName)) {
            try {
                instanceCache.put(implClassName, implClass.newInstance());
            } catch (InstantiationException | IllegalAccessException e) {
                String errorMsg = String.format("%s 类实例化失败", implClassName);
                throw new RuntimeException(errorMsg, e);
            }
        }

        return (T) instanceCache.get(implClassName);
    }

    /**
     * 加载指定 SPI 接口的实现映射
     *
     * @param loadClass SPI 接口类型
     * @return          实现映射（key -> 实现类）
     */
    public static Map<String, Class<?>> load(Class<?> loadClass) {
        log.info("加载类型为 {} 的 SPI", loadClass.getName());
        // 扫描路径，用户自定义的 SPI 优先级高于系统 SPI
        Map<String, Class<?>> keyClassMap = new HashMap<>();
        for (String scanDir : SCAN_DIRS) {
            List<URL> resources = ResourceUtil.getResources(scanDir + loadClass.getName());
            // 读取每个资源文件
            for (URL resource : resources) {
                try {
                    InputStreamReader inputStreamReader = new InputStreamReader(resource.openStream());
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        String[] strArray = line.split("=");
                        if (strArray.length > 1) {
                            String key = strArray[0];
                            String className = strArray[1];
                            keyClassMap.put(key, Class.forName(className));
                            log.debug("已加载 SPI 实现: {} -> {}", key, className);
                        }
                    }
                } catch (Exception e) {
                    log.error("spi resource load error", e);
                }
            }
        }
        loaderMap.put(loadClass.getName(), keyClassMap);
        return keyClassMap;
    }
}
